package com.reggie.dish.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.reggie.category.entity.Category;
import com.reggie.category.service.CategoryService;
import com.reggie.configuration.common.Result;
import com.reggie.configuration.myException.CustomException;
import com.reggie.dish.dao.DishDao;
import com.reggie.dish.entity.Dish;
import com.reggie.dish.entity.DishFlavor;
import com.reggie.dish.entity.dtos.DishDTO;
import com.reggie.dish.service.DishFlavorService;
import com.reggie.dish.service.DishService;
import com.reggie.setmeal.entity.SetmealDish;
import com.reggie.setmeal.service.SetmealDishService;
import com.reggie.setmeal.service.SetmealService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
@Transactional
public class DishServiceimpl extends ServiceImpl<DishDao, Dish> implements DishService {

    @Autowired
    private DishDao dao;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;

    //查看菜品是否关联套餐，如果关联则不能删除菜品
    @Autowired
    private SetmealDishService setmealDishService;

    //查看如果关联了套餐，就把套餐名取出来
    @Autowired
    private SetmealService setmealService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void saveWithFlavor(DishDTO dishDTO) {
        this.save(dishDTO);

        //同更新，都是为了更新Redis的脏数据
        String key = "dish_"+dishDTO.getCategoryId()+"_1";
        redisTemplate.delete(key);

        Long id = dishDTO.getId();
        //将每一个口味都赋值上ID
        List<DishFlavor> flavors = dishDTO.getFlavors();
        List<DishFlavor> collect = flavors.stream().map((item) -> {
            item.setDishId(id);
            return item;
        }).collect(Collectors.toList());
        //用口味都service存口味信息
        dishFlavorService.saveBatch(collect);
    }

    /**
     * 这个方法是对菜品进行查询对
     * TODO 这个方法不太理解，需要多研究一下,也不太理解为什么page对象可以作为返回值类型而且也可以被接收
     *
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @Override
    public Result<Page> selectByPage(int page, int pageSize, String name) {
        //分页功能必备对象
        IPage<Dish> pageDish = new Page<>(page, pageSize);
        //这个是要返回出去的对象，所以等会要将pageDish查好的数据全部拷贝过来，然后在赋值上口味的数据
        Page<DishDTO> pageDishDTO = new Page<>();

        QueryWrapper<Dish> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<Dish> lambda = queryWrapper.lambda();
        lambda.orderByDesc(Dish::getSort);
        //对名字进行模糊查询，如果名字为null的话就不拼接
        lambda.like(name != null, Dish::getName, name);
        //返回值也会返回原对象，所以不用接收也可以，这句代码是进行分页查询，pageDish是页码的信息，queryWrapper是对名字的模糊查询
        this.page(pageDish, queryWrapper);
        //拷贝结果,参数应该是原数据对象，要拷贝到的数据对象，第三个参数是忽略，忽略某个参数，因为这是Page对象
        //为什么不拷贝这个属性？因为这个records返回的是原泛型集合，而pageDishDTO需要的是DTO的集合，所以要忽略该属性
        BeanUtils.copyProperties(pageDish, pageDishDTO, "records");
        System.out.println("pageDish的records是：" + pageDish.getRecords());
        System.out.println("pageDishDTO的records是：" + pageDishDTO.getRecords());
        //getRecords会返回泛型传入的类型集合
        List<Dish> Dishes = pageDish.getRecords();
        //item代表着原对象也就是Dishes,map方法就是映射
        List<DishDTO> collect = Dishes.stream().map(item -> {

            DishDTO dto = new DishDTO();
            //将Dishes（item）的数据拷贝到dto里
            BeanUtils.copyProperties(item, dto);

            //根据id查询分类对象，然后将查询到的分类对象的名字赋值给DTO
            Long categoryId = item.getCategoryId();
            Category category = categoryService.getByID(categoryId);
            if (category != null) {
                //将分类名字赋给dto（不可能没有名字的）
                String categoryName = category.getName();
                dto.setCategoryName(categoryName);
            }   //Lambda接收Dishes（item）作为参数，然后遍历将自身每一个category.getName赋值给dto，然后将dto作为返回值return回去
            return dto;
        }).collect(Collectors.toList());

        pageDishDTO.setRecords(collect);

        return Result.success(pageDishDTO);
    }

    /**
     * 修改菜品信息
     *
     * @param dto
     */
    @Override
    @Transactional
    public void updateWithFlavor(DishDTO dto) {
        //先直接更新更新dish表的基本信息，因为dish表的字段dto都有，所以可以直接传递dto过去，表里没有的也不会赋值过去
        this.updateById(dto);

        //拼接Redis需要的key,然后根据key清楚redis中存的数据，以便更新数据
        String key = "dish_"+dto.getCategoryId()+"_1";
        redisTemplate.delete(key);

        //清理当前菜品对应口味数据---dish_flavor表的delete操作
        QueryWrapper<DishFlavor> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<DishFlavor> lambda = queryWrapper.lambda();
        //因为口味信息量有点多，不可控，所以直接全部删除重新关联
        lambda.eq(DishFlavor::getDishId, dto.getId());
        dishFlavorService.remove(queryWrapper);

        //添加新的口味信息
        List<DishFlavor> flavors = dto.getFlavors();

        List<DishFlavor> collect = flavors.stream().peek(item ->
                item.setDishId(dto.getId())).collect(Collectors.toList()
        );
        dishFlavorService.saveBatch(collect);
    }

    /**
     * 修改操作对数据回显
     *
     * @param id
     * @return
     */
    @Override
    public DishDTO getByIDwithFlavor(Long id) {
        //根据id先查询到菜品信息
        Dish dish = dao.selectById(id);

        DishDTO dto = new DishDTO();
        BeanUtils.copyProperties(dish, dto);
        //根据dish里的口味id来查口味集合
        QueryWrapper<DishFlavor> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<DishFlavor> lambda = queryWrapper.lambda();
        lambda.eq(DishFlavor::getDishId, dish.getId());
        //这个就是旧的口味集合
        List<DishFlavor> list = dishFlavorService.list(queryWrapper);
        dto.setFlavors(list);
        return dto;
    }

    /**
     * 这里使用了逻辑删除，在实体类的属性上加@TableLogic注解
     * 调用了套餐属性对selectSetmealNameByID方法对菜品所在对套餐对名字进行读取
     *
     * @param ids
     */
    @Override
    public void deleteByIDs(List<Long> ids) {
        //没有套餐售卖菜品了才可以删除菜品
        //那就去setmeal_dish表里查询数据
        //现在传过来的是菜品的id，要根据菜品的id来获取setmeal_dish表的setmealID
        QueryWrapper<SetmealDish> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<SetmealDish> lambda = queryWrapper.lambda();
        lambda.in(SetmealDish::getDishId, ids);

        //这条命令是在setmeal_dish表里按照dishID进行查找数据，因为一个菜品可能关联多个套餐，所以返回是个集合
        List<SetmealDish> list = setmealDishService.list(queryWrapper);

        if (list.size() > 0) {
            for (SetmealDish setmealDish : list) {
                //根据菜品id获取关联套餐信息
//            SetmealDTO dto = setmealService.selectByID(setmealDish.getSetmealId());
                String name = setmealService.selectSetmealNameByID(setmealDish.getSetmealId());

                if (name == null) {
                    dao.deleteById(setmealDish.getDishId());
                } else {
                    throw new CustomException(setmealDish.getName() + "菜品绑定了套餐" + name + "，不能删除");
                }
            }
        } else {
            dao.deleteBatchIds(ids);
        }

    }

    /**
     * 根据分类查询菜品(List方法)
     *
     * @param dish
     * @return
     */
    @Override
    public Result<List<DishDTO>> selectByCategoryID(Dish dish) {
        //先从Redis中获取数据，如果没有在查数据库，查了数据库以后也要缓存到Redis中去
        //拼接一个key
        String key = "dish_"+dish.getCategoryId()+"_"+dish.getStatus();

        List<DishDTO> dishDtoList = (List<DishDTO>) redisTemplate.opsForValue().get(key);

        if (dishDtoList!= null){
            return Result.success(dishDtoList);
        }

        //如果Redis数据库中不存在菜品信息，就构造查询条件进行查询,并将查询到的数据存到Redis数据库中去
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
        //添加条件，查询状态为1（起售状态）的菜品
        queryWrapper.eq(Dish::getStatus,1);
        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

        List<Dish> list = this.list(queryWrapper);

        dishDtoList = list.stream().map((item) -> {
            DishDTO dishDto = new DishDTO();
            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);
            if(category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            //当前菜品的id
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);

            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            dishDto.setFlavors(dishFlavorList);

            return dishDto;
        }).collect(Collectors.toList());
        System.out.println("菜品信息为:[ "+dishDtoList+" ]");
        //将MYSQL数据库中查到的数据存入Redis数据库中
        redisTemplate.opsForValue().set(key,dishDtoList,1, TimeUnit.HOURS);

        return Result.success(dishDtoList);
    }

    /**
     * 停售或启售菜品
     *
     * @param status
     * @param ids
     */
    @Override
    public void stopSellDish(int status, List<Long> ids) {
        QueryWrapper<Dish> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<Dish> lambda = queryWrapper.lambda();
        lambda.in(Dish::getId, ids);

        List<Dish> list = this.list(queryWrapper);

        for (Dish dish : list) {
            dao.updateStatus(dish.getId(), status);
        }


    }

}
